package com.haizhi.crm.search.builder;

import com.google.common.collect.Lists;
import com.haizhi.crm.search.model.SearchQo;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * Created by chengmo on 2018/5/30.
 */
public class SearchQoBuilder {

    private SearchQo searchQo = new SearchQo();

    /**
     * Gets a searchQo object.
     *
     * @return
     */
    public SearchQo get() {
        return searchQo;
    }

    /**
     * Sets graph name.
     *
     * @param graph
     * @return
     */
    public SearchQoBuilder setGraph(String graph) {
        this.searchQo.setGraph(graph);
        this.searchQo.setDomain(graph);
        return this;
    }

    /**
     * Sets keyword.
     *
     * @param keyword
     * @return
     */
    public SearchQoBuilder setKeyword(String keyword) {
        if (StringUtils.isNotBlank(keyword)) {
            this.searchQo.setKeyword(keyword);
        }
        return this;
    }

    /**
     * Sets page number.
     *
     * @param pageNo
     * @return
     */
    public SearchQoBuilder setPageNo(int pageNo) {
        this.searchQo.setPageNo(pageNo);
        return this;
    }

    /**
     * Sets page size.
     *
     * @param pageSize
     * @return
     */
    public SearchQoBuilder setPageSize(int pageSize) {
        this.searchQo.setPageSize(pageSize);
        return this;
    }

    /**
     * Adds schema names.
     *
     * @param schemas
     * @return
     */
    public SearchQoBuilder addSchemas(String... schemas) {
        this.searchQo.getSchemas().addAll(Arrays.asList(schemas));
        return this;
    }

    /**
     * Puts a pair <key,value> option.
     *
     * @param key
     * @param value
     * @return
     */
    public SearchQoBuilder putOption(String key, Object value) {
        this.searchQo.getOption().put(key, value);
        return this;
    }

    /**
     * Adds a field to the match query.
     *
     * @param field
     * @return
     */
    public SearchQoBuilder addMatchQuery(String field) {
        if (StringUtils.isNotBlank(field) && StringUtils.isNotBlank(searchQo.getKeyword())) {
            return this.addMatchQuery(field, 1.0F);
        }
        return this;
    }

    /**
     * Adds a field to the match query with boost.
     *
     * @param field
     * @param boost
     * @return
     */
    public SearchQoBuilder addMatchQuery(String field, float boost) {
        Map<String, Object> fieldMap = new HashMap<>();
        fieldMap.put(SKeys.FIELD_FIELD, field);
        fieldMap.put(SKeys.TYPE_FIELD, SKeys.MATCH_FIELD);
        fieldMap.put(SKeys.BOOST_FIELD, boost);
        this.searchQo.getQuery().add(fieldMap);
        return this;
    }

    /**
     * Adds a term filter.
     *
     * @param field
     * @param values
     * @return
     */
    public SearchQoBuilder addTermFilter(String field, Object... values) {
        if (StringUtils.isNotBlank(field) && values.length > 0 && values[0] != null
                && StringUtils.isNotBlank(values[0].toString())) {
            this.addTermFilter(field, Arrays.asList(values));
        }
        return this;
    }

    public SearchQoBuilder addTermMustNotFilter(String field, boolean mustNot, Object... values) {
        if (StringUtils.isNotBlank(field) && values.length > 0 && values[0] != null
                && StringUtils.isNotBlank(values[0].toString())) {
            if (StringUtils.isNotBlank(field) && values != null) {
                Map<String, Object> fieldMap = new HashMap<>();
                fieldMap.put(SKeys.FIELD_FIELD, field);
                fieldMap.put(SKeys.TYPE_FIELD, SKeys.TERM_FIELD);
                fieldMap.put(SKeys.MUST_NOT_FIELD, mustNot);
                fieldMap.put(SKeys.VALUES_FIELD, Arrays.asList(values));
                this.searchQo.getFilter().add(fieldMap);
            }
            return this;
        }
        return this;
    }

    /**
     * Adds a term filter.
     *
     * @param field
     * @param values
     * @return
     */
    public SearchQoBuilder addTermFilter(String field, Collection<Object> values) {
        if (StringUtils.isNotBlank(field) && values != null) {
            Map<String, Object> fieldMap = new HashMap<>();
            fieldMap.put(SKeys.FIELD_FIELD, field);
            fieldMap.put(SKeys.TYPE_FIELD, SKeys.TERM_FIELD);
            fieldMap.put(SKeys.VALUES_FIELD, new ArrayList<>(values));
            this.searchQo.getFilter().add(fieldMap);
        }
        return this;
    }

    /**
     * Adds a range filter.
     *
     * @param field
     * @param from
     * @param to
     * @return
     */
    public SearchQoBuilder addRangeFilter(String field, Object from, Object to) {
        if (StringUtils.isNotBlank(field)
                && from != null && StringUtils.isNotBlank(from.toString())
                && to != null && StringUtils.isNotBlank(to.toString())) {
            Map<String, Object> fieldMap = new HashMap<>();
            fieldMap.put(SKeys.FIELD_FIELD, field);
            fieldMap.put(SKeys.TYPE_FIELD, SKeys.RANGE_FIELD);
            Map<String, Object> range = new HashMap<>();
            range.put(SKeys.FROM_FIELD, from);
            range.put(SKeys.TO_FIELD, to);
            fieldMap.put(SKeys.RANGES_FIELD, Lists.newArrayList(range));
            this.searchQo.getFilter().add(fieldMap);
        }
        return this;
    }

    /**
     * Adds ranges filter.
     *
     * @param field
     * @param builder
     * @return
     */
    public SearchQoBuilder addRangeFilter(String field, RangeBuilder builder) {
        Map<String, Object> fieldMap = new HashMap<>();
        fieldMap.put(SKeys.FIELD_FIELD, field);
        fieldMap.put(SKeys.TYPE_FIELD, SKeys.RANGE_FIELD);
        fieldMap.put(SKeys.RANGES_FIELD, builder.ranges());
        this.searchQo.getFilter().add(fieldMap);
        return this;
    }

    public SearchQoBuilder addSort(String field, String order) {
        if (StringUtils.isNotBlank(field) && StringUtils.isNotBlank(order)) {
            Map<String, Object> fieldMap = new HashMap<>();
            fieldMap.put(SKeys.FIELD_FIELD, field);
            fieldMap.put(SKeys.ORDER_FIELD, order);
            this.searchQo.getSort().add(fieldMap);
        }
        return this;
    }

    public SearchQoBuilder addHitFields(String... fields) {
        this.searchQo.getFields().addAll(Arrays.asList(fields));
        return this;
    }
}
